package cn.z2huo.demo.mybatis.plus.service.optimisticlock;

import cn.z2huo.demo.mapper.system.OptimisticLockTestMapper;
import cn.z2huo.demo.model.dataobject.lock.OptimisticLockTestDO;
import cn.z2huo.demo.mybatis.plus.model.dto.lock.OptimisticLockTestDTO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * <p>
 *
 * @author z2huo
 */
@Service
@RequiredArgsConstructor
public class OptimisticLockTestServiceImpl implements OptimisticLockTestService {

    private final OptimisticLockTestMapper optimisticLockTestMapper;

    @Transactional
    @Override
    public void updateById(OptimisticLockTestDTO optimisticLockTestDTO) {
        Long id = optimisticLockTestDTO.getId();
        String name = optimisticLockTestDTO.getName();

        OptimisticLockTestDO optimisticLockTestDO = optimisticLockTestMapper.selectById(id);

        // 更新 name 字段
        LambdaUpdateWrapper<OptimisticLockTestDO> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.set(OptimisticLockTestDO::getName, name)
                .set(OptimisticLockTestDO::getOperateTime, LocalDateTime.now())
                .eq(OptimisticLockTestDO::getId, id)
                .eq(OptimisticLockTestDO::getOperateTime, optimisticLockTestDO.getOperateTime());
        int updateCount = optimisticLockTestMapper.update(updateWrapper);

        if (updateCount != 1) {
            throw new RuntimeException("更新失败");
        }
    }

    @Retryable(retryFor = OptimisticLockUpdateException.class,
            maxAttempts = 2,
            recover = "optimisticLockUpdateExceptionRecover",
            backoff = @Backoff(delay = 500))
    @Transactional
    public void updateByIdWithRetry(OptimisticLockTestDTO optimisticLockTestDTO) {
        Long id = optimisticLockTestDTO.getId();
        String name = optimisticLockTestDTO.getName();

        OptimisticLockTestDO optimisticLockTestDO = optimisticLockTestMapper.selectById(id);

        // 更新 name 字段
        LambdaUpdateWrapper<OptimisticLockTestDO> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.set(OptimisticLockTestDO::getName, name)
                .set(OptimisticLockTestDO::getOperateTime, LocalDateTime.now())
                .eq(OptimisticLockTestDO::getId, id)
                .eq(OptimisticLockTestDO::getOperateTime, optimisticLockTestDO.getOperateTime());
        int updateCount = optimisticLockTestMapper.update(updateWrapper);

        if (updateCount != 1) {
            throw new OptimisticLockUpdateException("更新失败，待重试");
        }
    }

    @Recover
    private void optimisticLockUpdateExceptionRecover() {
        throw new OptimisticLockUpdateException("更新失败");
    }
}
